/*
 * Copyright 2009 Cedric Priscal
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.serialport.sample;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.os.SystemClock;
import android.serialport.SerialPort;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;

public abstract class SerialPortActivity extends Activity {
    private static final String TAG = "SerialPortActivity";

    protected Application mApplication;
    protected SerialPort mSerialPort;
    protected OutputStream mOutputStream;
    private InputStream mInputStream;
    private ReadThread mReadThread;

    private class ReadThread extends Thread {

        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                int size;
                try {
                    byte[] buffer = new byte[132];
                    if (mInputStream == null) {
                        return;
                    }
                    size = mInputStream.read(buffer);
                    if (size != 132) {
                        SystemClock.sleep(300);
                        continue;
                    }
                    int dataStartIndex = findDataStartIndex(buffer);
                    if (dataStartIndex == -1) {
                        continue;
                    }
                    if (dataStartIndex == 0) {
                        // 刚好读取到
                        if (checkCRC(buffer)) {
                            onDataReceived(buffer, 132);
                        }
                    } else {
                        int offsetDataSize = Math.abs(132 - buffer.length - dataStartIndex);
                        byte[] offsetDataBuffer = new byte[offsetDataSize];
                        if (mInputStream.read(offsetDataBuffer) == offsetDataBuffer.length) {
                            System.arraycopy(buffer, dataStartIndex, buffer, 0, buffer.length - dataStartIndex);
                            System.arraycopy(offsetDataBuffer, 0, buffer, buffer.length - dataStartIndex, offsetDataSize);
                            if (checkCRC(buffer)) {
                                onDataReceived(buffer, 132);
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                SystemClock.sleep(50);
            }
        }
    }

    private boolean checkCRC(byte[] buffer) {
        int sumValue = 0;
        for (int i = 0; i < buffer.length - 1; i++) {
            sumValue += buffer[i];
        }
        int checkSum = sumValue & 0xFF;
        int checkResponseSum = buffer[buffer.length - 1];
        if (checkResponseSum < 0) {
            checkResponseSum += 256;
        }
        return checkSum == checkResponseSum;
    }

    private int findDataStartIndex(byte[] buffer) {
        for (int i = 0; i < buffer.length - 3; i++) {
            if (buffer[i] == -86 && buffer[i + 1] == -86 && buffer[i + 2] == -127) {
                return i;
            }
        }
        return -1;
    }

    private void DisplayError(int resourceId) {
        AlertDialog.Builder b = new AlertDialog.Builder(this);
        b.setTitle("Error");
        b.setMessage(resourceId);
        b.setPositiveButton("OK", new OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                SerialPortActivity.this.finish();
            }
        });
        b.show();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mApplication = (Application) getApplication();
        try {
            mSerialPort = mApplication.getSerialPort();
            mOutputStream = mSerialPort.getOutputStream();
            mInputStream = mSerialPort.getInputStream();

            /* Create a receiving thread */
            mReadThread = new ReadThread();
            mReadThread.start();
        } catch (SecurityException e) {
            DisplayError(R.string.error_security);
        } catch (IOException e) {
            DisplayError(R.string.error_unknown);
        } catch (InvalidParameterException e) {
            DisplayError(R.string.error_configuration);
        }
    }

    protected abstract void onDataReceived(final byte[] buffer, final int size);

    @Override
    protected void onDestroy() {
        if (mReadThread != null) {
            mReadThread.interrupt();
        }
        mApplication.closeSerialPort();
        mSerialPort = null;
        super.onDestroy();
    }
}
